#ifndef SOCKET_HPP_INCLUDED
#define SOCKET_HPP_INCLUDED

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h> //For errno - the error number
#include <netdb.h> //hostent
#include <unistd.h>

#include <string>
#include <string.h>

#include <sstream>
#include <iostream>

#include "common_MyException.h"
#include "common_ColaThreadSafe.h"

#include "common_Mensaje.h"

#include "common_Thread.h"

#define MAX_BUFF 500
#define DELIM "<L>"
#define DELIMSIZE 3

class Socket: public Thread{
    protected:
    int NumSocket;
    int Select(int Segundos);
    void GetInfoDelPeer(struct sockaddr_in& Info)
    {
        socklen_t size = sizeof(Info);
        int ret = getpeername(this->NumSocket,(struct sockaddr*)&Info,&size);
        if ( ret == -1 ){
            throw MyException("error fatal de getpeername"
                             + std::string(strerror(errno)) );
        }
    }

    public:

    Socket(int Sock):NumSocket(Sock){this->RAW = "";}
    Socket(){this->Inicializar();};

    int Close(){return close(this->NumSocket);}
    void ShutDown();
    virtual ~Socket() = 0 ;

    // 2 excepciones:
    // Se cerro la conexion del otro lado
    // Error Fatal en send
    void SendData(const std::string& Data);

    // 3 excepciones:
    // error en select #deprecated#
    // Se cerro la conexion del otro lado
    // Error Fatal en recv
    //BLOQUEA HASTA RECIBIR MENSAJE
    // si se lo quiere parar, hay que cancelarlo desde afuera
    void ReciveData( ColaThreadSafe<Mensaje>& Cola );

    private:
    std::string RAW; //diferencial entre bytes placa de red y procesados por mi
    void Inicializar();
    void Protocolo(std::string& str);
    void InversaProtocolo(std::string& str);
    bool ProcesarCrudo(std::string& MensRec);
};

#endif // SOCKET_HPP_INCLUDED
